<template>
  <div
    ref="erpListPage"
    class="erp-list-page"
  >
    <div
      class="erp-list-box"
    >
      <erp-search-tree
        v-if="searchTree && searchTreePosition === 'left'"
        :width="searchTreeWidth"
        :position="searchTreePosition"
        :props="searchTree.props"
        :search-key="searchTree.key"
        :data="treeSearchData"
        :api-list="searchTreeApiList"
        @search="handleTreeSearch"
      />
      <div
        ref="erpListTable"
        class="erp-list-table"
        :style="{width: 'calc(100% - ' + (searchTreeWidth ? searchTreeWidth + 15 : 0) +'px)', padding: tablePadding, 'padding-top': '0'}"
      >
        <erp-page-table
          ref="erpPageTable"
          :op-fixed="options.table.operationFixed"
          :table-props="computedTableProps"
          :is-tree="isTree"
          :tree-table="options.table.treeTable"
          :type="options.type"
          :data="dataListComputed"
          :permissions="options.table.permissions"
          :multiple-selected-ids="multipleSelectedIds"
          :loading.sync="loading"
          :show-header="options.table.showHeader"
          :height="tableHeight || options.table.height"
          :keyword-key="options.search.keywordKey"
          :total="options.table.total"
          :border="options.table.border"
          :fields="options.table.fields"
          :init-data="options.table.initData"
          :screen-list="options.search.screenList"
          :pagination="options.table.showPagination"
          :check-table="options.table.selectable"
          :default-expand-all="options.table.defaultExpandAll"
          :show-query="options.search.showAdvancedQuery"
          :show-export="options.table.showExport"
          :page-index.sync="pageIndex"
          :page-size="options.search.form.pageSize"
          :show-keyword-search="options.search.showKeywordQuery"
          :show-operation="options.table.showOperation"
          :advanced-search="options.search.advancedForm"
          :row-key="options.table.rowKey"
          :custom-column="options.table.customColumn"
          :show-order-number="options.table.showOrderNumber"
          :operation-width="options.table.operationWidth"
          :head-search-placeholder="options.search.headSearchPlaceholder"
          :tree-props="options.table.treeProps"
          :item-selectable="itemSelectableFunction"
          :head-buttons="headButtons"
          :operation-buttons="operationButtons"
          :data-source-api="options.apiList.dataSourceApi"
          :tree-search-key="searchTree ? searchTree.key : ''"
          :render="options.table.render"
          :edit-table-api="options.table.editTableApi"
          :order-number-width="options.table.orderNumberWidth"
          @size-change="handleSizeChange"
          @change-page="currentChange"
          @change-sort="handleSortChange"
          @search="handleSearch"
          @export="handleExport"
          @head-search="handleHeadSearch"
          @head-reset="handleHeadReset"
          @selection-change="handleSelectionChange"
          @select-change="handleSelectChange"
          @select-all-change="handleSelectAllChange"
          @search-keyword="handleKeywordSearch"
          @search-tree-table-keyword="handleSearchTreeTableKeyword"
          @batch-delete="handleBatchDelete"
          @toggle-advanced-box="handleToggleAdvancedBox"
          @get-tree-search-data="handleTreeSearchDataSource"
          @single-select-close="handleSingleSelect"
          @close-loading="handleCloseLoading"
        >
          <template
            v-for="item in tableColumnSlotList"
            :slot="item.prop + '__column_slot'"
            slot-scope="{row}"
          >
            <slot
              :name="item.prop + '__column_slot'"
              :row="row"
            />
          </template>
          <slot
            v-for="item in tableColumnSlotList"
            :slot="item.field + '__column_slot'"
            :name="item.field + '__column_slot'"
          />
          <template
            slot="operation"
            slot-scope="scope"
          >
            <div class="operation-button__text">
              <slot
                name="operation-buttons"
                :item="scope.row"
              />
              <el-button
                v-for="button in operationButtons"
                v-if="ifButton(button, scope.row) && buttonPermission(button)"
                v-show="visibleButton(button,scope.row)"
                :key="button.prop"
                v-bind="button.prop"
                :disabled="disabledButton(button, scope.row)"
                :type="button.prop && button.prop.type ? button.prop.type : 'text'"
                @click.stop="handleRowAction(button, scope.row)"
              >
                {{ button.text }}
              </el-button>
              <!--                            <el-button v-if="singleSelectAble"-->
              <!--                                       type="text"-->
              <!--                                       @click.stop="handleSingleSelect(scope.row)"-->
              <!--                            >-->
              <!--                                {{$t('common.select')}}-->
              <!--                            </el-button>-->
            </div>
          </template>
          <slot
            v-if="$slots.searchAdvanced"
            slot="search-advanced"
            name="search-advanced"
          />
          <template
            v-else
            slot="search-advanced"
          >
            <el-tab-pane
              v-for="(group, groupIndex) in groupForm"
              :key="groupIndex"
              :label="group.title || $t('common.erp.form.basicInfo')"
            >
              <el-row>
                <div
                  v-for="(item, index) in group.items"
                  :key="index"
                >
                  <erp-form-item
                    :item="item"
                    @update-field="handleSearchUpdateField"
                    @value-change="handleSearchValueChange"
                  />
                </div>
              </el-row>
            </el-tab-pane>
          </template>

          <template slot="handle-action">
            <slot name="head-buttons" />
            <el-button
              v-for="(button, index) in headButtons"
              v-if="buttonPermission(button)"
              :key="index"
              v-bind="button.prop"
              :type="button.props && button.props.type ? button.props.type : ''"
              class="handle-button"
              @click.stop="handleRowAction(button)"
            >
              {{ button.text }}
            </el-button>
          </template>
        </erp-page-table>
      </div>
      <erp-search-tree
        v-if="searchTree && searchTreePosition === 'right'"
        :width="searchTreeWidth"
        :position="searchTreePosition"
        :props="searchTree.props"
        :search-key="searchTree.key"
        :data="treeSearchData"
        @search="handleTreeSearch"
      />
    </div>
    <div v-if="components">
      <div>
        <component
          :is="'ErpListForm'"
          v-for="(component, componentKey) in components"
          v-if="component.active"
          :key="componentKey"
          :name="component.name"
          :title="component.title"
          :visible-dialog.sync="component.active"
          :query="component.query"
          :page-config-api="component.pageConfigApi"
          :data-source-api="component.dataSourceApi"
          :default-value-api="component.defaultValueApi"
          :width="component.width"
          :height="component.height"
          :type="component.type"
          @refresh="getList"
          @close="handleComponentClose(componentKey)"
          @query-list="handleQueryList"
        />
      </div>
    </div>
    <div v-if="assignComponents">
      <component
        :is="'ErpListAssign'"
        v-for="(component, componentKey) in assignComponents"
        v-if="component.value"
        :key="component.name"
        :value="component.value"
        :props="component.props"
        :extra="component.extra"
        :multiple="component.multiple"
        :options="component.options"
        :id-list="component.idList"
        :query="component.query"
        :request="component.request"
        :default-value="component.defaultValue"
        @value-change="handleAssignComponentValueChange($event, componentKey)"
      />
    </div>
  </div>
</template>

<script>
import Vue from 'vue';
import ErpPageTable from '@/components/erp/ErpPageTable';
import ErpPageTableColumn from '@/components/erp/ErpPageTable/ErpPageTableColumn';
import {toast} from '@/utils';
import {cloneJson, toString} from "@/utils";
import {Button, Col, FormItem, Input, Row} from "element-ui";
import ErpFormCol from "@/components/erp/ErpPageForm/ErpFormCol";
import ErpListForm from "@/components/erp/ErpListForm/ErpListForm";
import {base as request, collection} from '@/request';
import {findRouteByFullPath} from "../../../utils/route";
import XEUtils from 'xe-utils';

const ErpFormItem =  () => import('@/components/erp/ErpListForm/ErpFormItem');
const ErpListView = () => import('@/components/erp/ErpListView/ErpListView');
const ErpListAssign = () => import('@/components/erp/ErpListPage/ErpListAssign');
const ErpSearchTree = () => import('@/components/erp/ErpListPage/ErpSearchTree');
Vue.use(Input);
Vue.use(Button);
Vue.use(Row);
Vue.use(FormItem);
Vue.use(Col);

/**
 * 表格列表组件
 */
export default {
  name: "ErpListPage",
  components: {
    ErpFormCol,
    ErpPageTable,
    ErpPageTableColumn,
    ErpListForm,
    ErpFormItem,
    ErpListView,
    ErpListAssign,
    ErpSearchTree
  },
  beforeRouteLeave(to, from, next) {
    let _this = this;
    window.removeEventListener('resize', function () {
      _this.screenWidth = 0;
      _this.screenHeight = 0;
    });
    next();
  },
  props: {
    /**
     * [配置项](../eg/ErpListPage.html)
     * @public
     */
    options: {
      type: Object,
      default () {
        return {
          // list / singleSelect / multipleSelect
          type: "list",
          search: {
            tree: {
              "enable": true,
              "width": 200,
              "position": "left",
              "key": "departmentId",
              "props": {
                "data": [],
                "nodeKey": "id",
                "defaultExpandAll": true,
                "expandOnClickNode": false,
                "highlightCurrent": true,
                "showCheckbox": false,
                "props": {
                  "label": "name",
                  "children": "childs"
                }
              }
            }
          }
        };
      }
    },
    /**
     * 额外数据
     * @public
     */
    extraData: {
      type: [Object, Array],
      default: null
    },
    /**
     * 表格多选时选中的默认值
     * @public
     */
    multipleSelectedIds: {
      type: Array,
      default () {
        return [];
      }
    },
    /**
     * 表格属性，参考vxe-table的[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    tableProps: {
      type: Object,
      default () {
        return {};
      }
    }
  },
  data () {
    const search = this.options.search.form;
    return {
      treeSearchData: [],
      advanceQueryHeight: 0,
      tableLoading: true,
      loading: false,
      visibleForm: false,
      visibleView: false,
      modeView: 'view',
      mode: 'create',
      initSearch: search,
      search: cloneJson(search),
      checkedList: [],
      formItem: {},
      viewItem: {},
      tableHeight: null,
      assignComponents: [],
      dataList: null,
      screenWidth: document.documentElement.clientWidth,//屏幕宽度
      screenHeight: document.documentElement.clientHeight,//屏幕高度
      treeTableKeyword: null, // 树形表格搜索关键字
    };
  },
  computed: {
    //树形表格搜索字段名
    treeTableSearchProps () {
      return this.options && this.options.table && this.options.table.treeTable && this.options.table.treeTable.searchProps ? this.options.table.treeTable.searchProps : ['name'];
    },
    enableTreeTableSearch () {
      return !!(this.options && this.options.table && this.options.table.treeTable && this.options.table.treeTable.showKeywordSearch);
    },
    childrenKey () {
      return this.options && this.options.table && this.options.table.props && this.options.table.props.treeConfig && this.options.table.props.treeConfig.children ? this.options.table.props.treeConfig.children : 'name';
    },
    dataListComputed () {
      const filterName = toString(this.treeTableKeyword) ? toString(this.treeTableKeyword).trim().toLowerCase() : null;
      if (this.enableTreeTableSearch && filterName) {
        let options = {children: this.childrenKey};
        const searchProps = this.treeTableSearchProps;
        return XEUtils.searchTree(this.dataList, item => searchProps.some(key => toString(item[key]) ? toString(item[key]).toLowerCase().indexOf(filterName) > -1 : false), options);
      }
      return this.dataList;
    },
    tablePadding () {
      if (this.options && this.options.table && this.options.table.padding) {
        return this.options.table.padding;
      }
      return '15px';
    },
    tableColumnSlotList: function () {
      let fields = this.options && this.options.table && this.options.table.fields ? cloneJson(this.options.table.fields) : [];
      return fields.filter((item) => {
        return item.type === 'slot';
      });
    },
    disabledButton () {
      return function (button, row) {
        if (button.disabledFunction) {
          try{
            return new Function("row", button.disabledFunction )(row);
          }catch (e) {
            console.log('disabledFunction error');
            console.log(e);
          }
        }
        return button.props && button.props.disabled !== undefined ? button.props.disabled : false;
      };
    },
    ifButton () {
      return function (button, row) {
        if (button.ifFunction) {
          try{
            return new Function("row", button.ifFunction )(row);
          }catch (e) {
            console.log('ifFunction error');
            console.log(e);
          }
        }
        return true;
      };
    },
    visibleButton () {
      return function (button, row) {
        if (button.visibleFunction) {
          try{
            return new Function("row", button.visibleFunction )(row);
          }catch (e) {
            console.log('visibleFunction error');
            console.log(e);
          }
        }
        return true;
      };
    },
    type () {
      if (this.options && (this.options.type === "single" || this.options.type === "multiple")) {
        return this.options.type;
      }
      return "list";
    },
    groupForm () {
      let groupForm = [];
      let form = this.search;
      let formList = this.options.search.advancedForm;
      if (formList && formList.length > 0) {
        for (let i in formList) {
          if (!this.visibleFunc(formList[i])){
            continue;
          }
          if (form[formList[i].field] !== undefined) {
            formList[i].value = form[formList[i].field];
          }
          let group = formList[i].group || '';
          let hasGroup = false;
          if (groupForm && groupForm.length > 0) {
            for (let j in groupForm) {
              let groupTitle = groupForm[j].title || '';
              if (group === groupTitle) {
                hasGroup = true;
                groupForm[j].items.push(formList[i]);
                break;
              }
            }
          }
          if (!hasGroup) {
            let groupRow = {
              title: group,
              items: [formList[i]]
            };
            groupForm.push(groupRow);
          }
        }
      }
      return groupForm;
    },
    // 搜索框表单配置
    advancedSearch () {
      let form = {};
      let formList = this.options.search.advancedForm;
      if (formList && formList.length > 0) {
        for (let i in formList) {
          form[formList[i].field] = formList[i].value;
        }
      }
      return form;
    },
    headButtons () {
      let array = [];
      let buttons = this.options && this.options.buttons ? this.options.buttons : [];
      if (buttons && buttons.length > 0) {
        for (let i in buttons) {
          if (buttons[i].position === 'head') {
            array.push(buttons[i]);
          }
        }
      }
      return array;
    },
    components: {
      get () {
        let options = this.options;
        return options && options.components ? options.components : [];
      },
      set (components) {
        let options = Object.assign({}, this.options);
        options.components = components;
        this.$emit('change-options', options);
      }
    },

    operationButtons () {
      let array = [];
      let buttons = this.options && this.options.buttons ? this.options.buttons : [];
      if (buttons && buttons.length > 0) {
        for (let i in buttons) {
          if (buttons[i].position === 'operation') {
            array.push(buttons[i]);
          }
        }
      }
      return array;
    },
    deleteAble () {
      return !(this.options && this.options.handleList && this.options.handleList.delete && this.options.handleList.delete.enable === false);
    },
    singleSelectAble () {
      return !!(this.options && this.options.type && this.options.type === 'singleSelect');
    },
    multipleSelectAble () {
      return !!(this.options && this.options.type === 'multipleSelect');
    },
    isTree () {
      return this.options && this.options.table && this.options.table.isTree === true;
    },
    itemSelectableFunction () {
      if (this.options && this.options.table && this.options.table.itemSelectableFunction) {
        try{
          return new Function('return ' + this.options.table.itemSelectableFunction)();
        }catch(e) {
          return null;
        }
      }
      return null;
    },
    showPagination () {
      return !(this.options && this.options.table && this.options.table.showPagination === false);
    },
    showHeader () {
      return !(this.options && this.options.table && this.options.table.showHeader === false);
    },
    height () {
      if (this.options && this.options.table && this.options.table.height) {
        return this.options.table.height;
      }
      return null;
    },
    padding () {
      let options = this.options;
      if (options.style && options.style.padding) {
        return options.style.padding;
      }
      return '15px';
    },
    pageIndex: {
      get () {
        let a = this.options && this.options.search && this.options.search.form && this.options.search.form.pageIndex ? this.options.search.form.pageIndex : 1;
        return a;
      },
      set (val) {
        let options = this.options;
        options.search.form.pageIndex = val;
        this.search.pageIndex = val;
        this.$emit('update:options', Object.assign({}, options));
      }
    },
    buttonPermission () {
      return function (button) {
        let permissions = button.permissions;
        if (!permissions || permissions.length === 0) {
          return true;
        }
        let permissionButtons = this.$store.state.permission.permissions;
        if (!permissionButtons || permissionButtons.length === 0) {
          return true;
        }
        for (let i in permissions) {
          if (permissions[i] && permissionButtons.indexOf(permissions[i]) > -1) {
            return true;
          }
        }
        return false;
      };
    },
    searchTree () {
      return this.options && this.options.search && this.options.search.tree && this.options.search.tree.enable === true ? this.options.search.tree : null;
    },
    searchTreeWidth () {
      if (this.searchTree) {
        if (this.searchTree.width) {
          return this.searchTree.width;
        }
        return 200;
      }
      return 0;
    },
    // 树形结构数据
    searchTreeApiList () {
      if (this.searchTree && this.searchTree.apiList) {
        return this.searchTree.apiList;
      }
      return {};
    },
    searchTreePosition () {
      if (this.searchTree) {
        return this.searchTree.position;
      }
      return "left";
    },
    editTableApi () {
      return this.options && this.options.table && this.options.table.editTableApi ? this.options.table.editTableApi : '';
    },
    insertTableApi () {
      if (this.editTableApi) {
        return this.editTableApi.insert;
      }
      return null;
    },
    updateTableApi () {
      if (this.editTableApi) {
        return this.editTableApi.update;
      }
      return null;
    },
    deleteTableApi () {
      if (this.editTableApi) {
        return this.editTableApi.delete;
      }
      return null;
    },
    computedTableProps () {
      let props = this.options && this.options.table && this.options.table.props ? this.options.table.props : {};
      let tableProps = this.tableProps;
      return Object.assign(props, tableProps);
    }
  },
  watch: {
    'screenWidth' () { //监听屏幕宽度变化
      if (!this.height) {
        this.fetchTableHeight();
      }
    },
    'screenHeight' () { //监听屏幕高度变化
      if (!this.height) {
        this.fetchTableHeight();
      }
    },
    'tableProps.syncResize' (newVal, oldVal) {
      if (newVal !== oldVal) {
        this.fetchTableHeight();
      }
    },
    loading (l) {
      this.$emit('change-loading', l);
    }
  },
  mounted () {
    let _this = this;
    window.addEventListener('resize', function(){ // 定义窗口大小变更通知事件
      _this.screenWidth = document.documentElement.clientWidth; //窗口宽度
      _this.screenHeight = document.documentElement.clientHeight; //窗口高度
    });
    if (!this.height) {
      this.fetchTableHeight();
    }
    this.generateAssignComponents();
  },
  methods: {
    /**
     * 关闭加载状态
     * @private
     */
    handleCloseLoading () {
      this.loading = false;
    },
    /**
     * 分配组件的值更新
     * @private
     * @param data
     * @param index
     */
    handleAssignComponentValueChange (data, index) {
      this.assignComponents[index].value = data;
    },
    /**
     * 树形搜索
     * @private
     * @param search
     */
    handleTreeSearch (search) {
      let item = {search: search};
      this.handleSearch(item);
    },
    /**
     * 生成分配组件
     * @private
     */
    generateAssignComponents () {
      let assignComponents = [];
      if (this.options) {
        let buttons = this.options.buttons;
        if (buttons && buttons.length > 0) {
          for (let i in buttons ) {
            if (buttons[i].actionType === 'assign') {
              assignComponents.push(buttons[i].component);
            }
          }
        }
      }
      this.assignComponents = assignComponents;
    },
    /**
     * 监听组件关闭
     * @private
     * @param componentKey
     */
    handleComponentClose (componentKey) {
      let components = this.components;
      components[componentKey].active = false;
      this.components = Object.assign({}, components);
    },
    /**
     * 查询列表
     * @private
     * @param form
     */
    handleQueryList (form) {
      this.search = Object.assign(this.search, form);
      this.getList();
    },
    /**
     * 公共的询问框
     * @private
     * @param {object} confirmConfig 询问框配置{title, message, showCancelButton, type, confirmButtonText, cancelButtonText}
     * @returns {Promise<unknown>}
     */
    commonConfirm (confirmConfig) {
      return new Promise((resolve, reject) => {
        if (confirmConfig && confirmConfig.message) {
          this.$msgbox({
            title: confirmConfig.title || this.$t('common.tip'),
            message: confirmConfig.message,
            showCancelButton: confirmConfig.showCancelButton || true,
            type: confirmConfig.type || 'warning',
            showClose: confirmConfig.showClose || true,
            confirmButtonText: confirmConfig.confirmButtonText || this.$t('common.confirm'),
            cancelButtonText: confirmConfig.cancelButtonText || this.$t('common.cancel'),
          }).then(() => {
            resolve(true);
            return true;
          }).catch(err => {
            resolve(false);
            return false;
          });
        } else {
          resolve(true);
          return true;
        }
      });
    },
    /**
     * 显示或隐藏表单项
     * @param {object} item 表单项配置项
     * @private
     */
    visibleFunc (item) {
      if (item.visibleFunction) {
        let form = this.search;
        let field = item.field;
        try{
          return new Function('form','field', item.visibleFunction )(form, field);
        }catch(e) {
          console.log('visibleFunction error');
          console.log(e);
          return true;
        }
      }
      return true;
    },
    /**
     * 点击按钮之后触发，[参考](../eg/Button.html#listButton)
     * @private
     * @param button
     * @param row
     * @returns {Promise<boolean>}
     */
    async handleRowAction (button, row) {
      button = cloneJson(button);
      if (await this.commonConfirm(button.confirm)) {
        let query = this.generateQuery(button, row, this.$route.query, this.search, this.extraData, this.checkedList);
        if (button.actionType === 'dialog') {
          // 弹出窗
          let components = this.components;
          if (components) {
            for (let key in components) {
              components[key].active = button.componentKey === key;
              if (button.componentKey === key) {
                components[key].query = query;
              }
            }
          }
          this.components = Object.assign({}, components);
        } else if (button.actionType === 'delete') {
          // 删除
          let rowKey = this.options.table.rowKey;
          let deleteApi = button.actionApi || '';
          if (deleteApi) {
            this.loading = true;
            request.post(deleteApi,query || {[rowKey]: row[rowKey]})
              .then(() => {
                toast({
                  message: this.$t('common.deleteSuccess'),
                  type: 'success'
                });
                this.loading = false;
                this.getList();
              })
              .catch(() => {
                this.loading = false;
              });
          }
        } else if (button.actionType === 'batchDelete') {
          // 批量删除
          let rowKey = this.options.table.batchDeleteRowKey || this.options.table.rowKey || 'id';
          let idList = [];
          let checkedList = this.checkedList;
          for (let i in checkedList) {
            idList.push(checkedList[i][rowKey]);
          }
          if (!idList || idList.length === 0) {
            toast({
              message: '请先选择要操作的项',
              type: 'warning'
            });
            return false;
          }
          let deleteApi = button.actionApi || '';
          if (deleteApi) {
            this.loading = true;
            let key = this.options.table.batchDeleteKey || 'ids';
            request.post(deleteApi,query || {[key]: idList})
              .then(() => {
                toast({
                  message: '操作成功',
                  type: 'success'
                });
                this.getList();
                this.loading = false;
              })
              .catch(() => {
                this.loading = false;
              });
          }
        } else if (button.actionType === 'singleSelect') {
          // 单选
          this.$emit('single-select-close', {item: row});
        } else if (button.actionType === 'insertTable') {
          // 插入到表格
          this.$refs.erpPageTable.$refs.table.$refs.erpTable.insert();
        } else if (button.actionType === 'saveTable') {
          // 保存表格
          if (!await this.fullValidTable()) {
            return false;
          }
          const { insertRecords, removeRecords, updateRecords } = this.$refs.erpPageTable.$refs.table.$refs.erpTable.getRecordset();
          let emptyInsert = true;
          let emptyUpdate = true;
          let emptyDelete = true;
          if (insertRecords && insertRecords.length > 0) {
            emptyInsert = false;
            if (!await this.tableBatchInsert(insertRecords)){
              return false;
            }
          }
          if (removeRecords && removeRecords.length > 0) {
            emptyDelete = false;
            if (!await this.tableBatchDelete(removeRecords)) {
              return false;
            }
          }
          if (updateRecords && updateRecords.length > 0) {
            emptyUpdate = false;
            if (!await this.tableBatchUpdate(updateRecords)) {
              return false;
            }
          }
          if (emptyInsert && emptyUpdate && emptyDelete) {
            toast({
              message: '数据未发生变更',
              type: 'warning'
            });
            return false;
          }
          this.getList();
          toast({
            message: this.$t('common.saveSuccess'),
            type: 'success'
          });
        } else if (button.actionType === 'deleteTableRows') {
          // 删除选中的表格行
          this.$refs.erpPageTable.$refs.table.$refs.erpTable.removeCheckboxRow();
        } else if (button.actionType === 'revertTable') {
          // 还原表格
          this.$refs.erpPageTable.$refs.table.$refs.erpTable.revertData()
            .then(() => {
              toast({
                message: '数据还原成功',
                type: 'success'
              });
            });

        } else if (button.actionType === 'refreshTable') {
          // 刷新表格
          this.getList()
            .then(() => {
              toast({
                message: '数据已刷新',
                type: 'success'
              });
            });
        } else if (button.actionType === 'assign') {
          // 分配，用于员工分配
          let rowKey = this.options.table.rowKey;
          let idList = row[rowKey];
          let assignComponents = cloneJson(this.assignComponents);
          if (assignComponents) {
            for (let index in assignComponents) {
              assignComponents[index].value = button.component.name === assignComponents[index].name;
              assignComponents[index].query = query;
              assignComponents[index].idList = idList;
            }
          }
          this.assignComponents = Object.assign([], assignComponents);
        } else if (button.actionType === 'route') {
          await this.$router.push(findRouteByFullPath(button.props.path));
        } else if (button.actionType === 'emitButton') {
          this.$emit('emit-button', {button, row});
        }
      }
    },
    /**
     * 生成额外参数
     * @private
     * @param button
     * @param row
     * @param routeQuery
     * @param search
     * @param extraData
     * @param checkedList
     * @returns {null|*}
     */
    generateQuery (button, row, routeQuery, search, extraData, checkedList) {
      if (button.queryFunction) {
        try {
          return new Function('row', 'query', 'search', button.queryFunction)(row, routeQuery, search);
        }catch (e) {
          return null;
        }
      } else {
        let query = button.query;
        if (!query) {
          return null;
        }
        for (let i in query) {
          if (typeof query[i] === 'string' && query[i].substr(0, 2) === '$_' && query[i].length > 2) {
            let field = query[i].substr(2);
            if (row && row[field] !== undefined) {
              query[i] = row[field];
            }
          }else if (typeof query[i] === 'string' && query[i].substr(0,3) === '$s_' && query[i].length > 3) {
            let searchField = query[i].substr(3);
            if (search[searchField] !== undefined) {
              query[i] = search[searchField];
            }
          }else if (extraData && typeof query[i] === 'string' && query[i].substr(0,3) === '$e_' && query[i].length > 3) {
            let extraField = query[i].substr(3);
            if (extraData[extraField] !== undefined) {
              query[i] = extraData[extraField];
            }
          } else if (checkedList && typeof query[i] === 'string'  && query[i].substr(0,3) === '$b_' && query[i].length > 3) {
            // 批量操作的数据，比如批量删除需要的id
            let checkedField = query[i].substr(3);
            let checkedValue = [];
            for (let j in checkedList) {
              checkedValue.push(checkedList[j][checkedField]);
            }
            checkedValue = checkedValue.length > 0 ? checkedValue.join(',') : '';
            query[i] = checkedValue;
          }
        }

        return query || null;
      }
    },
    /**
     * 根据搜索条件搜索列表
     * @public
     * @param {object} item 搜索对象，{search}
     */
    handleSearch (item) {
      this.search = Object.assign(this.search, item.search);
      let options = Object.assign({}, this.options);
      options.search.form = this.search;
      this.$emit('update:options',  options);
      this.getList();
    },
    handleCloseForm () {
      this.visibleForm = false;
    },
    /**
     * 获取列表
     * @public
     * @param {object} search 额外搜索对象
     * @returns {Promise<unknown>}
     */
    getList () {
      return new Promise((resolve, reject) => {
        this.loading = true;
        let options = this.options;

        if (options && options.search && options.search.formFunction) {
          let formSearch = this.getFormFromFunction( this.extraData, options.search.formFunction);
          this.search = Object.assign(this.search, formSearch);
        }


        let listApi = this.options && this.options.apiList && this.options.apiList.list ? this.options.apiList.list : '';
        let api = listApi;
        let type = 'post';
        let baseUrlType = 'base';
        if(typeof listApi === 'object') {
          api = listApi.url || '';
          type = listApi.type || 'post';
          baseUrlType = listApi.baseUrlType || 'base';
        }

        if (api) {
          let requestMethod = request[type];
          if (baseUrlType === 'collection') {
            requestMethod = collection[type];
          }
          let params = this.search;
          if (type === 'get') {
            requestMethod = request[type];
            params = {params: this.search};
          }

          requestMethod(api, params)
            .then(res => {
              let list = [];
              if (res.data) {
                list = res.data.list;
              }
              this.dataList = list;
              this.$emit('list-change', list);
              let options = this.options;
              options.table.list = list;
              options.table.total = res.data && res.data.total ? res.data.total : 0;
              this.$emit('update:options', options);
              this.checkedList = [];
              this.loading = false;
              if(this.dataList == null) {
                this.dataList = [];
                this.loading = false;
              }
              resolve();
            })
            .catch(() => {
              this.dataList = [];
              this.loading = false;
              reject();
            })
            .finally(() => {
            });
        }
      });
    },
    /**
     * 通过额外数据生成到列表的搜索请求对象中
     * @private
     * @param {*} data list的额外数据extraData
     * @param {string} functionStr 字符串函数
     * @returns {*}
     */
    getFormFromFunction (data, functionStr) {
      if (functionStr) {
        try{
          return new Function('data', "query", functionStr)(data, this.$route.query);
        }catch(e) {
          console.log('getFormFromFunction error');
          console.log(e);
        }
      }
      return this.search;
    },
    /**
     * 更改分页页码时触发
     * @private
     * @param index
     */
    currentChange (index) {
      this.pageIndex = index;
      this.getList();
    },
    /**
     * 更改分页容量大小时触发
     * @private
     * @param size
     */
    handleSizeChange (size) {
      this.pageIndex = 1;
      this.search.pageSize = size;
      this.getList();
    },
    /**
     * 更改字段排序时触发
     * @private
     * @param data
     */
    handleSortChange: function (data) {
      if (data) {
        this.search.pageOrderBy = data.property;
        let dir = null;
        if (data.order === 'asc') {
          dir = 1;
        } else if (data.order === 'desc') {
          dir = 2;
        }
        this.search.pageOrderDir = dir;
        this.getList();
      }
    },
    /**
     * 导出时触发【未实现】
     * @private
     * @param form
     */
    handleExport (form) {
      console.log(form);
    },
    /**
     * 高级查询时触发
     * @public
     * @param {object} form 搜索表单{search}
     */
    handleHeadSearch (form) {
      this.pageIndex = 1;
      this.handleSearch({search: form});
    },
    /**
     * 高级查询重置触发
     * @private
     */
    handleHeadReset () {
      this.search = Object.assign(this.search, this.initSearch);
      this.pageIndex = 1;
      this.handleSearch({search: this.search});
    },
    /**
     * 批量操作时触发
     * @private
     * @returns {Promise<boolean>}
     */
    async handleBatchDelete () {
      let idList = [];
      let rowKey = this.options.table.rowKey;

      let checkedList = this.checkedList;
      for (let i in checkedList) {
        idList.push(checkedList[i][rowKey]);
      }
      if (!idList || idList.length === 0) {
        toast({
          message: this.$t('common.pleaseSelectWhatYouWantDelete'),
          type: 'error'
        });
        return false;
      }
      if (await this.commonConfirm(this.options.handleList.batchDelete.confirm)) {
        let deleteApi = this.options && this.options.apiList && this.options.apiList.batchDelete ? this.options.apiList.batchDelete : '';

        this.batchDeleteLoading = true;
        let key = this.options.handleList.batchDelete.rowsKey || 'ids';
        request.post(deleteApi,{[key]: idList})
          .then(() => {
            toast({
              message: this.$t('common.deleteSuccess'),
              type: 'success'
            });
            this.getList();
          });
      }
    },
    /**
     * 单选或多选时，选项更新时触发
     * @private
     * @param val
     */
    handleSelectionChange (val) {
      this.checkedList = val;
    },
    /**
     * 列表为多选时，获取到选项值
     * @private
     * @param val
     */
    handleSelectChange (val) {
      this.checkedList = val.selection;
      if (this.multipleSelectAble) {
        this.$emit('multiple-select-change', val);
      }
      this.$bus.$emit("handleSelectionChange", val)
    },
    /**
     * 全选时触发
     * @private
     * @param val
     */
    handleSelectAllChange (val) {
      this.checkedList = val.selection;
      if (this.multipleSelectAble) {
        this.$emit('multiple-select-all-change', val);
      }
    },
    /**
     * 关键字查询
     * @private
     * @param keywordObj
     */
    handleKeywordSearch (keywordObj) {
      this.pageIndex = 1;
      this.handleSearch({
        search: keywordObj
      });
    },
    /**
     * 树表格搜索关键字
     * @private
     * @param data
     */
    handleSearchTreeTableKeyword (data) {
      this.treeTableKeyword = data;
    },
    /**
     * 重新计算表格高度
     * @private
     * @returns {Promise<unknown>}
     */
    resetHeight() {
      return new Promise((resolve, reject) => {
        this.tableHeight = 0;
        resolve();
      });
    },
    /**
     * 获取表格高度
     * @private
     * @returns {Promise<unknown>}
     */
    fetchTableHeight () {
      this.resetHeight().then(() => {
        let emptyHeight = 110;
        if (!this.showPagination) {
          emptyHeight = emptyHeight - 33;
        }
        if (!this.showHeader) {
          emptyHeight = emptyHeight - 46;
        }
        this.tableHeight = this.$refs.erpListPage.parentNode.getBoundingClientRect().height - emptyHeight - this.advanceQueryHeight;
      });
    },
    /**
     * 搜索表单更新其他字段
     * @private
     * @param fieldObj
     */
    handleSearchUpdateField (fieldObj) {
      let form = this.search;
      if (form) {
        for (let i in form) {
          if (fieldObj[i] !== undefined) {
            form[i] = fieldObj[i];
          }
        }
      }
    },
    /**
     * 搜索表单更新值
     * @private
     * @param obj
     */
    handleSearchValueChange (obj) {
      let form = this.search;
      if (obj.field) {
        form[obj.field] = obj.value;
      }
      this.search = form;
    },
    /**
     * 打开/关闭高级查询框
     * @private
     * @param obj
     */
    handleToggleAdvancedBox (obj) {
      this.advanceQueryHeight = obj.height;
      this.fetchTableHeight();
    },
    /**
     * 获取树查询的数据源
     * @private
     * @param data
     */
    handleTreeSearchDataSource (data) {
      this.treeSearchData = data;
    },
    /**
     * 通过字符串函数生成查询表单
     * @private
     * @param row
     * @param query
     * @param formFunction
     * @returns {*}
     */
    generateTableForm (row, query, formFunction) {
      if (formFunction) {
        try{
          return new Function('form','query', formFunction)(row, query);
        }catch (e) {
          console.log('formFunction error');
          console.log(e);
        }
      }
      return row;
    },
    /**
     * 表格批量插入数据
     * @private
     * @param data
     * @returns {Promise<boolean>}
     */
    async tableBatchInsert(data) {
      if (data && data.length > 0 && this.insertTableApi && this.insertTableApi.url) {
        for (let i in data) {
          if (!await this.tableSingleInsert(data[i])){
            return false;
          }
        }
      }
      return true;
    },
    /**
     * 表格插入一行
     * @private
     * @param row
     * @returns {Promise<unknown>}
     */
    tableSingleInsert (row) {
      return new Promise((resolve, reject) => {
        let form = this.generateTableForm(Object.assign({}, row), this.extraData, this.insertTableApi.formFunction);
        request.post(this.insertTableApi.url, form)
          .then(res => {
            resolve(true);
            return true;
          })
          .catch(error => {
            resolve(false);
            return false;
          });
      });
    },
    /**
     * 编辑表格批量删除
     * @private
     * @param data
     * @returns {Promise<boolean>}
     */
    async tableBatchDelete(data) {
      if (data && data.length > 0 && this.deleteTableApi && this.deleteTableApi.url) {
        for (let i in data) {
          if (!await this.tableSingleDelete(data[i])){
            return false;
          }
        }
      }
      return true;
    },
    /**
     * 表格当行删除
     * @private
     * @param row
     * @returns {Promise<unknown>}
     */
    tableSingleDelete (row) {
      return new Promise((resolve, reject) => {
        let form = this.generateTableForm(Object.assign({}, row), this.extraData, this.deleteTableApi.formFunction);
        request.post(this.deleteTableApi.url, form)
          .then(res => {
            resolve(true);
            return true;
          })
          .catch(error => {
            resolve(false);
            return false;
          });
      });
    },
    /**
     * 表格批量更新
     * @private
     * @param data
     * @returns {Promise<boolean>}
     */
    async tableBatchUpdate(data) {
      if (data && data.length > 0 && this.updateTableApi && this.updateTableApi.url) {
        for (let i in data) {
          if (!await this.tableSingleUpdate(data[i])){
            return false;
          }
        }
      }
      return true;
    },
    /**
     * 表格单行更新
     * @private
     * @param row
     * @returns {Promise<unknown>}
     */
    tableSingleUpdate (row) {
      return new Promise((resolve, reject) => {
        let form = this.generateTableForm(Object.assign({}, row), this.extraData, this.updateTableApi.formFunction);
        request.post(this.updateTableApi.url, form)
          .then(res => {
            resolve(true);
            return true;
          })
          .catch(error => {
            resolve(false);
            return false;
          });
      });
    },
    /**
     * 编辑表格全量验证
     * @private
     * @returns {Promise<boolean>}
     */
    async fullValidTable () {
      const errMap = await this.$refs.erpPageTable.$refs.table.$refs.erpTable.fullValidate().catch(errMap => errMap);
      if (errMap) {
        let msgList = [];
        Object.values(errMap).forEach(errList => {
          errList.forEach(params => {
            let { rowIndex, column, rules } = params;
            rules.forEach(rule => {
              msgList.push(`第 ${rowIndex + 1} 行 ${column.title} 校验错误：${rule.message}`);
            });
          });
        });
        let html = '';
        if (msgList && msgList.length > 0) {
          for (let i in msgList) {
            html += '<div>' + msgList[i] + '</div>';
          }
        }
        toast({
          dangerouslyUseHTMLString: true,
          message: html,
          type: "error"
        });
        return false;
      }
      return true;
    },
    /**
     * 单选时触发
     * @private
     * @param row
     */
    handleSingleSelect (row) {
      if (this.options && this.options.type === 'singleSelect') {
        this.$emit('single-select-close', {item: row});
      }
    },
    /**
     * 重新计算表格尺寸
     * @public
     * @param refull
     */
    recalculate (refull) {
      this.$refs.erpPageTable.recalculate(refull);
    }
  }
};
</script>

<style lang="scss" scoped>
    $primaryColor: var(--primary-color);
.erp-list-page{
    .erp-list-box{
        display: flex;
        flex-wrap: nowrap;
        .erp-list-table{
            /*box-shadow: 0px 0px 10px 0px rgba(5, 5, 5, 0.1);*/
            background-color: #fff;
            padding: 15px;
            padding-top:0;
        }
    }
}
.handle-button {
    &::v-deep{
        background-color: #EBF1FF;;
        color: $primaryColor;
        border: 1px solid $primaryColor;
    }
    &:last-child{
        margin-right: 2px;
    }
}
</style>
